package com.zjun.core.spel;

import com.zjun.annotation.Idempotent;
import com.zjun.core.AbstractIdempotentExecuteHandler;
import com.zjun.core.IdempotentAspect;
import com.zjun.core.IdempotentContext;
import com.zjun.core.IdempotentParamWrapper;
import com.zjun.exception.ClientException;
import com.zjun.toolkit.SpELUtil;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;

@RequiredArgsConstructor
public class IdempotentSpelByRestAPIExecuteHandler extends AbstractIdempotentExecuteHandler implements IdempotentSpelService {
    private final RedissonClient redissonClient;
    private final static String LOCK = "lock:spEl:restAPI";

    @SneakyThrows
    @Override
    protected IdempotentParamWrapper buildWrapper(ProceedingJoinPoint joinPoint) {
        Idempotent idempotent = IdempotentAspect.getIdempotent(joinPoint);
        String key = (String) SpELUtil.parseKey(idempotent.key(), ((MethodSignature) joinPoint.getSignature()).getMethod(), joinPoint.getArgs());
        return IdempotentParamWrapper.builder().localKey(key).idempotent(idempotent).joinPoint(joinPoint).build();
    }

    @Override
    public void handler(IdempotentParamWrapper wrapper) {
        String uniqueKey = wrapper.getIdempotent().uniqueKeyPrefix()+ wrapper.getLocalKey();
        RLock lock = redissonClient.getLock(uniqueKey);
        if (!lock.tryLock()){
            throw new ClientException(wrapper.getIdempotent().message());
        }
        IdempotentContext.put(LOCK,lock);
    }

    @Override
    public void exceptionProcessing() {
        RLock lock = null;
        try {
            lock = (RLock) IdempotentContext.getKey(LOCK);
        }finally {
            if (lock != null){
                lock.unlock();
            }
        }
    }

    @Override
    public void postProcessing() {
        RLock lock = null;
        try {
            lock = (RLock) IdempotentContext.getKey(LOCK);
        }finally {
            if (lock != null){
                lock.unlock();
            }
        }
    }
}
